import cv2
import math  

from PIL import Image, ImageDraw, ImageFont  
from math import radians, degrees  
import numpy as np
from numpy import uint8
from loguru import logger

from app.models import Dev,Station

from cv.ocr.ocr import ocr_img_ali
from app.core.conf import ST


class BaseImg:

    __slots__ = ('img_raw', 'dev','station','ocr_raw_list','img_draw','img_mask','timestamp','img_ing')


    def __init__(self,dev:Dev,station:Station,img_raw:uint8,timestamp:int) -> None:
        # 机台信息
        self.dev = dev
        # 站点信息
        self.station = station
        # 原图片
        self.img_raw = img_raw
        # 专门用来绘图的图片
        self.img_draw = img_raw.copy()
        # 专门用来蒙版的图片 
        self.img_mask = img_raw.copy()
        # ocr识别的内容
        self.ocr_raw_list = []

        self.timestamp = timestamp


    def show(self,img,title='default'):
        cv2.namedWindow(title,cv2.WINDOW_NORMAL)
        cv2.imshow(title,img)  
        cv2.waitKey()
        cv2.destroyAllWindows() 
 

    def ocr_img(self):
        self.ocr_raw_list = ocr_img_ali(self.img_raw)


    def ocr_blur_img(self):
        # 进行高斯模糊  
        blur = cv2.GaussianBlur(self.img_raw, (5, 5), 0)  # kernel_size为(11, 11)，标准差为0 
        self.ocr_raw_list = ocr_img_ali(blur)


    def ocr_scale(self):
        # 获取图像的高度和宽度  
        height, width = self.img_raw.shape[:2]  
        # 缩放图像  
        resized_img = cv2.resize(self.img_raw, (int(width/2), int(height/2)), interpolation=cv2.INTER_AREA)  
        self.img_draw = resized_img
        self.ocr_raw_list = ocr_img_ali(resized_img)
        
  

    def log_ocr(self):
        for ocr in self.ocr_raw_list:
            logger.debug(ocr)


    def highlight_ocr(self,ocr_raw_list=None):
        if not ocr_raw_list:
            ocr_raw_list =self.ocr_raw_list
        for data in ocr_raw_list:
            # 计算矩形的中心点和角度
            x, y, w, h = data['x'], data['y'], data['w'], data['h']  
            center = (x + w / 2, y + h / 2)
            angle = data['a'] 
            # 创建旋转矩形对象
            rotated_rect = (center, (w, h), angle)
            # 获取旋转矩形的四个顶点坐标
            box = cv2.boxPoints(rotated_rect)
            box = np.int0(box)
            # 填充旋转矩形, 创建一张相同大小的纯黑色图片  
            mask_black_img = np.zeros_like(self.img_raw).astype(np.uint8) * 0
            cv2.fillPoly(mask_black_img,[box], (255, 255, 255))
            # 创建一张相同大小的纯黑色图片  
            img_mask = cv2.bitwise_and(self.img_raw, mask_black_img)
            data['img'] = self.__crop_ocr_img(img_mask)
            

    

    def __crop_ocr_img(self,image):
        img_blur = cv2.medianBlur(image, 5)
        # self.show(img_blur,'blur')
        img_hsv=cv2.cvtColor(img_blur,cv2.COLOR_BGR2HSV)
        # self.show(img_hsv,'hsv')
        img_ing = cv2.inRange(img_hsv,(1,1,1) ,(180,255,255))
        # self.show(img_ing,'hsv')
        img_ing = cv2.dilate(img_ing,np.ones((5,5),np.int8),iterations=1)
        # self.show(img_ing,'dilate')
        # 查找轮廓
        contours, _ = cv2.findContours(img_ing,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
        # logger.debug(len(contours))
        rect_count = len(contours)

        if rect_count < 1 or rect_count > 1:
            logger.error('检测到矩形<1 or >1，不符合')
            return None

        x,y,w,h = cv2.boundingRect(contours[0])  #轮廓的边界矩形，x,y是矩形左上角的坐标，w,h是矩形的宽度和高度
        return self.crop_img((x,y,w,h))


    def crop_img(self,pos):
        x,y,w,h = pos
        return self.img_raw[y:y+h,  x:x+w]


    def draw_rect(self,pos):
        x,y,w,h = pos
        self.img_draw =  cv2.rectangle(self.img_draw,(x,y),(x+w,y+h),(0,255,0),3)
            

    def detect_color(self,hsv:tuple):
        img_blur = cv2.medianBlur(self.img_raw, 5)
        # self.show(img_blur)
        img_hsv=cv2.cvtColor(img_blur,cv2.COLOR_BGR2HSV)
        # self.hsv_slider(img_hsv)
        self.img_ing = cv2.inRange(img_hsv,hsv[0],hsv[1])
        # self.show(self.img_ing)


    def detect_glass(self):
        self.detect_color(((0,0,100),(180,255,255)))
        self.img_ing = self.erode(self.img_ing,(5,5),1)
        # self.show(self.img_ing)
        self.img_ing = self.dilate(self.img_ing,(15,10),3)
        # self.show(self.img_ing)
        continue_flag = self.find_rect_pos((100,50))
        if continue_flag == ():
            logger.debug('重新拍照识别');
            return True
        filtered_image = cv2.bitwise_and(self.img_raw, self.img_raw,mask=self.img_ing)
        cv2.imwrite(ST.IMG_DRAW_PATH+"\\"+str(self.timestamp)+'.jpg',filtered_image)
        return False

    def detect_glass_new(self):
        self.detect_color(((0,0,100),(180,255,255)))
        self.img_ing = self.erode(self.img_ing,(5,5),1)
        # self.show(self.img_ing)
        self.img_ing = self.dilate(self.img_ing,(15,10),3)
        # self.show(self.img_ing)
        continue_flag = self.find_rect_pos((100,50))
        if continue_flag == ():
            logger.debug('重新拍照识别');
            return True
        filtered_image = cv2.bitwise_and(self.img_raw, self.img_raw,mask=self.img_ing)
        return filtered_image
        # cv2.imwrite(ST.IMG_DRAW_PATH+"\\"+str(self.timestamp)+'.jpg',filtered_image)
        # return False




    
    def erode(self,img,kernel_size:tuple,count:int):
        # 形态学处理,腐蚀
        kernel = np.ones(kernel_size,np.int8)
        return cv2.erode(img,kernel,iterations=count) 
 
 
    def dilate(self,img,kernel_size:tuple,count:int):
        """形态学处理,膨胀
        Args:
            img (_type_): 图片 
            kernel_size (tuple): 例：(5,5) 
            count (int): 膨胀的次数 

        Returns:
            _type_: _description_
        """
        kernel = np.ones(kernel_size,np.int8)
        return cv2.dilate(img,kernel,iterations=count)

    def draw_ocr(self,ocr_filter_text_list):
        for ocr_text in ocr_filter_text_list:
 
            self.img_draw = Image.fromarray(cv2.cvtColor(self.img_draw, cv2.COLOR_BGR2RGB))
            x =ocr_text.get('x')
            y =ocr_text.get('y')
            w = ocr_text.get('w')
            rotated_coord_list = BaseImg.rotate_ocr_coord(ocr_text)
            text_draw = ocr_text.get('t')
            draw = ImageDraw.Draw(self.img_draw)
            fontText = ImageFont.truetype(
                "font/simsun.ttc", 30, encoding="utf-8")
            draw.text((x+1.5*w, y), text_draw, (0, 255, 0), font=fontText)
            # 绘制完中文文字之后,再将图片转换回来
            self.img_draw =  cv2.cvtColor(np.asarray(self.img_draw), cv2.COLOR_RGB2BGR)
            # 绘制矩形框
            pts = np.array([i for i in rotated_coord_list],np.int32)
            pts.reshape((-1,1,2))
            cv2.polylines(self.img_draw,[pts],True,(0, 255, 0),thickness=2)



    @staticmethod
    def save_raw(timestamp,img):
        cv2.imwrite(ST.IMG_RAW_PATH+"\\"+str(timestamp)+'.jpg',img)

 
    @staticmethod
    def save_draw(timestamp,img):
        cv2.imwrite(ST.IMG_DRAW_PATH+"\\"+str(timestamp)+'.jpg',img)

        
    @staticmethod
    def rotate_ocr_coord(ocr_info):
        """_将ocr返回的坐标信息,按照Angle旋转之后在返回_
        Args:
            ocr_text (_type_): _ocr的文字和坐标信息_
        Returns:
            _type_: _旋转自后的四个顶点,不一定是矩形,所以要使用polyline来画边_
        """
        x =ocr_info.get('x')
        y =ocr_info.get('y')
        w =ocr_info.get('w')
        h =ocr_info.get('h')
        angle = ocr_info.get('a')
 
        M = cv2.getRotationMatrix2D((x + w*0.5, y +h*0.5),angle,1)
        coord_list = [(x,y),(x+w,y),(x+w,y+h),(x,y+h)]
 
        rotated_coord_list = [M.dot(np.array([coord[0],coord[1],1])) for coord in coord_list]
        return rotated_coord_list
 
     
    """
    功能：读取一张图片，显示出来，转化为HSV色彩空间
        并通过滑块调节HSV阈值，实时显示
    """
    def hsv_slider(self,img=None):
        if img is None:
            image = self.img_raw
        else:
            image = img
 
 
        hsv_low = np.array([0, 0, 0])
        hsv_high = np.array([0, 0, 0])
 
        # 下面几个函数，写得有点冗余
        def h_low(value):
            hsv_low[0] = value
        
        def h_high(value):
            hsv_high[0] = value
        
        def s_low(value):
            hsv_low[1] = value
        
        def s_high(value):
            hsv_high[1] = value
        
        def v_low(value):
            hsv_low[2] = value
        
        def v_high(value):
            hsv_high[2] = value
        
        #H low：
        #    0：指向整数变量的可选指针，该变量的值反映滑块的初始位置。
        #  179：表示滑块可以达到的最大位置的值为179，最小位置始终为0。
        #h_low：指向每次滑块更改位置时要调用的函数的指针，指针指向h_low元组，有默认值0。
        # （此函数的原型应为void XXX (int, void *); ，其中第一个参数是轨迹栏位置，第二个参数是用户数据（请参阅下一个参数）。如果回调是NULL指针，则不调用任何回调，而仅更新值。）
        cv2.namedWindow('image',cv2.WINDOW_AUTOSIZE)
        cv2.createTrackbar('H low', 'image', 0, 179, h_low) 
        cv2.createTrackbar('H high', 'image', 0, 179, h_high)
        cv2.createTrackbar('S low', 'image', 0, 254, s_low)
        cv2.createTrackbar('S high', 'image', 0, 254, s_high)
        cv2.createTrackbar('V low', 'image', 0, 254, v_low)
        cv2.createTrackbar('V high', 'image', 0, 254, v_high)

        cv2.namedWindow('raw',cv2.WINDOW_AUTOSIZE)
        cv2.imshow('raw', image)

        
        while True:
            dst = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # BGR转HSV
            dst = cv2.inRange(dst, hsv_low, hsv_high) # 通过HSV的高低阈值，提取图像部分区域
            cv2.namedWindow('dst',cv2.WINDOW_AUTOSIZE)
            cv2.imshow('dst', dst)
            if cv2.waitKey(1) & 0xFF == ord('q'):
                break
 
        
        return tuple(hsv_low),tuple(hsv_high)
         
    def find_rect_pos(self,threshold=(0,0)):
        # #查找轮廓
        contours, _ = cv2.findContours(self.img_ing,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
        pos_list = []
 
        for contour in  contours:
            x,y,w,h = cv2.boundingRect(contour)  #轮廓的边界矩形，x,y是矩形左上角的坐标，w,h是矩形的宽度和高度
            print(x,y,w,h)
            
            if w>threshold[0] and h>threshold[1]:
                pos_list.append((x,y,w,h))

        if len(pos_list) == 0:
            return ()
            # raise Exception(f'threshold={threshold}==>没有检测矩形,请调整阈值')
        elif len(pos_list)==1:        #如果长度为1,直接返回
            return pos_list[0]